package org.jeecg.modules.basic.materialtype.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.FillRuleConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.util.FillRuleUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.common.system.vo.SelectTreeModel;
import org.jeecg.modules.basic.customer.entity.BasicCustomer;
import org.jeecg.modules.basic.material.entity.BasicMaterial;
import org.jeecg.modules.basic.material.mapper.BasicMaterialMapper;
import org.jeecg.modules.basic.materialtype.entity.BasicMaterialTreeVO;
import org.jeecg.modules.basic.materialtype.entity.BasicMaterialType;
import org.jeecg.modules.basic.materialtype.mapper.BasicMaterialTypeMapper;
import org.jeecg.modules.basic.materialtype.service.IBasicMaterialTypeService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description: 物料分类
 * @Author: jeecg-boot
 * @Date:   2023-07-26
 * @Version: V1.0
 */
@Service
public class BasicMaterialTypeServiceImpl extends ServiceImpl<BasicMaterialTypeMapper, BasicMaterialType> implements IBasicMaterialTypeService {

    @Autowired
    private ISysBaseAPI iSysBaseAPI;
    @Autowired
    private BasicMaterialMapper basicMaterialMapper;

	@Override
	public void addBasicMaterialType(BasicMaterialType basicMaterialType) {
	   //新增时设置hasChild为0
	    basicMaterialType.setHasChild(IBasicMaterialTypeService.NOCHILD);
		if(oConvertUtils.isEmpty(basicMaterialType.getPid())){
			basicMaterialType.setPid(IBasicMaterialTypeService.ROOT_PID_VALUE);
		}else{
			//如果当前节点父ID不为空 则设置父节点的hasChildren 为1
			BasicMaterialType parent = baseMapper.selectById(basicMaterialType.getPid());
			if(parent!=null && !"1".equals(parent.getHasChild())){
				parent.setHasChild("1");
				baseMapper.updateById(parent);
			}
		}
		baseMapper.insert(basicMaterialType);
	}
	
	@Override
	public void updateBasicMaterialType(BasicMaterialType basicMaterialType) {
		BasicMaterialType entity = this.getById(basicMaterialType.getId());
		if(entity==null) {
			throw new JeecgBootException("未找到对应实体");
		}
        // 如果当前物料分类下有下级物料分类，则不可禁用
        if ("0".equals(basicMaterialType.getStatus()) && "1".equals(entity.getHasChild())) {
            throw new JeecgBootException("该物料分类下有下级分类，不可禁用！");
        }

		String old_pid = entity.getPid();
		String new_pid = basicMaterialType.getPid();
		if(!old_pid.equals(new_pid)) {
			updateOldParentNode(old_pid);
			if(oConvertUtils.isEmpty(new_pid)){
				basicMaterialType.setPid(IBasicMaterialTypeService.ROOT_PID_VALUE);
			}
			if(!IBasicMaterialTypeService.ROOT_PID_VALUE.equals(basicMaterialType.getPid())) {
				baseMapper.updateTreeNodeStatus(basicMaterialType.getPid(), IBasicMaterialTypeService.HASCHILD);
			}
		}
		baseMapper.updateById(basicMaterialType);
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteBasicMaterialType(String id) throws JeecgBootException {
        // 检验是否有子类
        BasicMaterialType basicMaterialType = this.getById(id);
        if ("1".equals(basicMaterialType.getHasChild())) {
            throw new JeecgBootException("该物料分类下有下级分类，不可删除！");
        }
        // 校验物料分类下是否有物料信息
        Long count = basicMaterialMapper.selectCount(new LambdaQueryWrapper<BasicMaterial>()
                .eq(BasicMaterial::getMaterialTypeId, id));
        if (count > 0) {
            throw new JeecgBootException("物料分类下已有物料信息，请删除物料后，再删除物料分类！");
        }
        //查询选中节点下所有子节点一并删除
        id = this.queryTreeChildIds(id);
        if(id.indexOf(",")>0) {
            StringBuffer sb = new StringBuffer();
            String[] idArr = id.split(",");
            for (String idVal : idArr) {
                if(idVal != null){
                    String pidVal = basicMaterialType.getPid();
                    //查询此节点上一级是否还有其他子节点
                    List<BasicMaterialType> dataList = baseMapper.selectList(new QueryWrapper<BasicMaterialType>().eq("pid", pidVal).notIn("id",Arrays.asList(idArr)));
                    boolean flag = (dataList == null || dataList.size() == 0) && !Arrays.asList(idArr).contains(pidVal) && !sb.toString().contains(pidVal);
                    if(flag){
                        //如果当前节点原本有子节点 现在木有了，更新状态
                        sb.append(pidVal).append(",");
                    }
                }
            }
            //批量删除节点
            baseMapper.deleteBatchIds(Arrays.asList(idArr));
            //修改已无子节点的标识
            String[] pidArr = sb.toString().split(",");
            for(String pid : pidArr){
                this.updateOldParentNode(pid);
            }
        }else{
            if(basicMaterialType==null) {
                throw new JeecgBootException("未找到对应实体");
            }
            updateOldParentNode(basicMaterialType.getPid());
            baseMapper.deleteById(id);
        }
	}
	
	@Override
    public List<BasicMaterialType> queryTreeListNoPage(QueryWrapper<BasicMaterialType> queryWrapper) {
        List<BasicMaterialType> dataList = baseMapper.selectList(queryWrapper);
        List<BasicMaterialType> mapList = new ArrayList<>();
        for(BasicMaterialType data : dataList){
            String pidVal = data.getPid();
            //递归查询子节点的根节点
            if(pidVal != null && !IBasicMaterialTypeService.NOCHILD.equals(pidVal)){
                BasicMaterialType rootVal = this.getTreeRoot(pidVal);
                if(rootVal != null && !mapList.contains(rootVal)){
                    mapList.add(rootVal);
                }
            }else{
                if(!mapList.contains(data)){
                    mapList.add(data);
                }
            }
        }
        return mapList;
    }

    @Override
    public List<SelectTreeModel> queryListByCode(String parentCode) {
        String pid = ROOT_PID_VALUE;
        if (oConvertUtils.isNotEmpty(parentCode)) {
            LambdaQueryWrapper<BasicMaterialType> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(BasicMaterialType::getPid, parentCode);
            List<BasicMaterialType> list = baseMapper.selectList(queryWrapper);
            if (list == null || list.size() == 0) {
                throw new JeecgBootException("该编码【" + parentCode + "】不存在，请核实!");
            }
            if (list.size() > 1) {
                throw new JeecgBootException("该编码【" + parentCode + "】存在多个，请核实!");
            }
            pid = list.get(0).getId();
        }
        return baseMapper.queryListByPid(pid, null);
    }

    @Override
    public List<SelectTreeModel> queryListByPid(String pid) {
        if (oConvertUtils.isEmpty(pid)) {
            pid = ROOT_PID_VALUE;
        }
        return baseMapper.queryListByPid(pid, null);
    }

    /**
     * 查询树形结构所有数据
     * @return
     */
    @Override
    public List<BasicMaterialTreeVO> listTree() {
        List<BasicMaterialType> list = this.list(new LambdaQueryWrapper<BasicMaterialType>()
                .eq(BasicMaterialType::getPid, "0")
                .eq(BasicMaterialType::getStatus, "1"));
        List<BasicMaterialTreeVO> treeVOList = new ArrayList<>();
        for (BasicMaterialType materialType : list) {
            BasicMaterialTreeVO vo = new BasicMaterialTreeVO();
            vo.setId(materialType.getId());
            vo.setName(materialType.getName());
            vo.setChildren(this.getChildTree(materialType));
            treeVOList.add(vo);
        }
        return treeVOList;
    }

    /**
     * 查询节点下的所有子节点id
     * @return
     */
    @Override
    public List<String> listIdsByPid(String id) {
        String ids = this.queryTreeChildIds(id);
        return Arrays.asList(ids.split(","));
    }

    /**
     * 导入
     * @param request
     * @return
     */
    @Override
    public Result<String> importExcel(HttpServletRequest request) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            // 获取上传文件对象
            MultipartFile file = entity.getValue();
            ImportParams params = new ImportParams();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                List<DictModel> dictList = iSysBaseAPI.getDictItems("inspect_info");
                List<String> inspects = dictList.stream().map(DictModel::getValue).collect(Collectors.toList());
                List<BasicMaterialType> list = ExcelImportUtil.importExcel(file.getInputStream(), BasicMaterialType.class, params);
                for (BasicMaterialType type : list) {
                    if (org.apache.commons.lang.StringUtils.isBlank(type.getName())) {
                        return Result.error("文件导入失败:分类名称不能为空！");
                    }
                    if (StringUtils.isBlank(type.getStatus())) {
                        return Result.error("文件导入失败:状态不能为空！");
                    }
                    if (!"0".equals(type.getStatus()) && !"1".equals(type.getStatus())) {
                        return Result.error("文件导入失败:状态只能填启用或禁用！");
                    }
                    if (StringUtils.isBlank(type.getHasChild())) {
                        return Result.error("文件导入失败:是否有子节点不能为空！");
                    }
                    if (!"0".equals(type.getHasChild()) && !"1".equals(type.getHasChild())) {
                        return Result.error("文件导入失败:是否有子节点只能填是或否！");
                    }
                    String[] split = type.getInspect().split(",");
                    for (int i = 0; i < split.length; i++) {
                        if (!inspects.contains(split[i])) {
                            return Result.error("文件导入失败:检验信息填写错误！");
                        }
                    }
                    List<BasicMaterialType> names = this.list(new LambdaQueryWrapper<BasicMaterialType>()
                            .eq(BasicMaterialType::getName, type.getName()));
                    if (CollectionUtil.isNotEmpty(names)) {
                        return Result.error("文件导入失败:分类名称 "+type.getName()+" 系统中已存在！");
                    }
                    Object result = FillRuleUtil.executeRule(FillRuleConstant.BASIC_CUSTOMER, new JSONObject());
                    type.setCode(result.toString());
                    if (StringUtils.isBlank(type.getPid())) {
                        type.setPid("0");
                    }
                }
                this.saveBatch(list);
                return Result.OK("文件导入成功！数据行数：" + list.size());
            } catch (Exception e) {
                String msg = e.getMessage();
                log.error(msg, e);
                if(msg!=null && msg.indexOf("Duplicate entry")>=0){
                    return Result.error("文件导入失败:有重复数据！");
                }else{
                    return Result.error("文件导入失败:" + e.getMessage());
                }
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.error("文件导入失败！");
    }

    /**
     * 递归查所有子节点
     * @param materialType
     * @return
     */
    private List<BasicMaterialTreeVO> getChildTree(BasicMaterialType materialType) {
        List<BasicMaterialTreeVO> treeList = new ArrayList<>();
        if ("1".equals(materialType.getHasChild())) {
            List<BasicMaterialType> list = this.list(new LambdaQueryWrapper<BasicMaterialType>()
                    .eq(BasicMaterialType::getPid, materialType.getId())
                    .eq(BasicMaterialType::getStatus, "1"));
            for (BasicMaterialType type : list) {
                BasicMaterialTreeVO vo = new BasicMaterialTreeVO();
                vo.setId(type.getId());
                vo.setName(type.getName());
                vo.setChildren(this.getChildTree(type));
                treeList.add(vo);
            }
        }
        return treeList;
    }

    /**
	 * 根据所传pid查询旧的父级节点的子节点并修改相应状态值
	 * @param pid
	 */
	private void updateOldParentNode(String pid) {
		if(!IBasicMaterialTypeService.ROOT_PID_VALUE.equals(pid)) {
			Long count = baseMapper.selectCount(new QueryWrapper<BasicMaterialType>().eq("pid", pid));
			if(count==null || count<=1) {
				baseMapper.updateTreeNodeStatus(pid, IBasicMaterialTypeService.NOCHILD);
			}
		}
	}

	/**
     * 递归查询节点的根节点
     * @param pidVal
     * @return
     */
    private BasicMaterialType getTreeRoot(String pidVal){
        BasicMaterialType data =  baseMapper.selectById(pidVal);
        if(data != null && !IBasicMaterialTypeService.ROOT_PID_VALUE.equals(data.getPid())){
            return this.getTreeRoot(data.getPid());
        }else{
            return data;
        }
    }

    /**
     * 根据id查询所有子节点id
     * @param ids
     * @return
     */
    private String queryTreeChildIds(String ids) {
        //获取id数组
        String[] idArr = ids.split(",");
        StringBuffer sb = new StringBuffer();
        for (String pidVal : idArr) {
            if(pidVal != null){
                if(!sb.toString().contains(pidVal)){
                    if(sb.toString().length() > 0){
                        sb.append(",");
                    }
                    sb.append(pidVal);
                    this.getTreeChildIds(pidVal,sb);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 递归查询所有子节点
     * @param pidVal
     * @param sb
     * @return
     */
    private StringBuffer getTreeChildIds(String pidVal,StringBuffer sb){
        List<BasicMaterialType> dataList = baseMapper.selectList(new QueryWrapper<BasicMaterialType>()
                .eq("pid", pidVal)
                .eq("status", "1"));
        if(dataList != null && dataList.size()>0){
            for(BasicMaterialType tree : dataList) {
                if(!sb.toString().contains(tree.getId())){
                    sb.append(",").append(tree.getId());
                }
                this.getTreeChildIds(tree.getId(),sb);
            }
        }
        return sb;
    }

    @Override
    public void updateUsedState(String materialTypeId) {
        Long aLong = basicMaterialMapper.selectCount(new LambdaQueryWrapper<BasicMaterial>()
                .eq(BasicMaterial::getMaterialTypeId, materialTypeId));
        BasicMaterialType materialType = new BasicMaterialType();
        materialType.setId(materialTypeId);
        if (aLong > 0){
            materialType.setUsed(1);
        }else {
            materialType.setUsed(0);
        }
        baseMapper.updateById(materialType);
    }
}
